#include "esp_rom_sys.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_log.h>
#include <driver/gpio.h>


// 配置DHT22连接的GPIO引脚（根据实际接线修改）
#define DHT22_PIN GPIO_NUM_4
// 日志标签
#define TAG "DHT22"

/**
 * @brief 读取DHT22温湿度数据
 * @param humidity 湿度指针（输出，单位：%RH）
 * @param temperature 温度指针（输出，单位：℃）
 * @return true 读取成功，false 读取失败
 */
bool dht22_read(float *humidity, float *temperature) {
    uint8_t data[5] = {0}; // 存储：湿度高8位、湿度低8位、温度高8位、温度低8位、校验位
    int timeout;

    // 步骤1：发送起始信号（主机拉低总线≥1ms）
    gpio_set_direction(DHT22_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(DHT22_PIN, 0);
    esp_rom_delay_us(18000); // 拉低18ms（远超最小1ms要求）
    gpio_set_level(DHT22_PIN, 1);
    esp_rom_delay_us(30); // 释放总线30μs（符合T_go：10-200μs）
    gpio_set_direction(DHT22_PIN, GPIO_MODE_INPUT);

    // 步骤2：检测传感器响应信号（低电平80μs）
    timeout = 0;
    while (gpio_get_level(DHT22_PIN) == 1) { // 等待总线拉低
        esp_rom_delay_us(1);
        if (++timeout > 100) { // 超时阈值>85μs，防止误判
            ESP_LOGE(TAG, "No response (low)");
            return false;
        }
    }

    // 检测响应高电平（80μs）
    timeout = 0;
    while (gpio_get_level(DHT22_PIN) == 0) { // 等待总线拉高
        esp_rom_delay_us(1);
        if (++timeout > 100) {
            ESP_LOGE(TAG, "No response (high)");
            return false;
        }
    }

    // 步骤3：读取40位数据（高位先出）
    for (int i = 0; i < 40; i++) {
        // 等待数据位低电平（50μs）
        timeout = 0;
        while (gpio_get_level(DHT22_PIN) == 1) {
            esp_rom_delay_us(1);
            if (++timeout > 60) { // 超过最大55μs超时
                ESP_LOGE(TAG, "Data low timeout");
                return false;
            }
        }

        // 测量高电平持续时间（区分0/1）
        timeout = 0;
        while (gpio_get_level(DHT22_PIN) == 0) {
            esp_rom_delay_us(1);
            if (++timeout > 60) {
                ESP_LOGE(TAG, "Data high timeout");
                return false;
            }
        }
        esp_rom_delay_us(40); // 等待40μs后判断（位0高电平≤30μs，位1≥68μs）

        // 高位先存，高电平持续>40μs则为1
        data[i/8] <<= 1;
        if (gpio_get_level(DHT22_PIN) == 1) {
            data[i/8] |= 1;
        }
    }

    // 步骤4：校验和验证（校验位=湿度高+湿度低+温度高+温度低）
    if (data[4] != (data[0] + data[1] + data[2] + data[3])) {
        ESP_LOGE(TAG, "Checksum error");
        return false;
    }

    // 步骤5：解析数据（湿度=16位值/10，温度=16位值/10，最高位判断正负）
    *humidity = (data[0] << 8 | data[1]) / 10.0f;
    int16_t temp_raw = data[2] << 8 | data[3];
    if (temp_raw & 0x8000) { // 最高位为1表示负温度
        *temperature = -(temp_raw & 0x7FFF) / 10.0f;
    } else {
        *temperature = temp_raw / 10.0f;
    }

    return true;
}

/**
 * @brief DHT22读取任务（周期2秒，符合最小采样间隔）
 */
void dht22_task(void *pvParameters) {
    // 上电后等待2秒，越过不稳定状态
    vTaskDelay(pdMS_TO_TICKS(2000));
    ESP_LOGI(TAG, "DHT22 task started");

    float humidity, temperature;
    while (1) {
        if (dht22_read(&humidity, &temperature)) {
            ESP_LOGI(TAG, "Humidity: %.1f %%RH, Temperature: %.1f ℃", humidity, temperature);
        } else {
            ESP_LOGE(TAG, "Failed to read data");
        }
        // 间隔2秒读取（符合最小间隔要求）
        vTaskDelay(pdMS_TO_TICKS(2000));
    }
}

void app_main(void) {
    // 初始化GPIO（默认上拉，增强信号稳定性）
    gpio_reset_pin(DHT22_PIN);
    gpio_set_pull_mode(DHT22_PIN, GPIO_PULLUP_ONLY); // 建议外接4.7kΩ上拉电阻

    // 创建读取任务
    xTaskCreate(dht22_task, "dht22_task", 2048, NULL, 5, NULL);
}